home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / doom / quake.zip / KASCAM17.ZIP / SOURCE / KASCAM.QC < prev    next >
Text File  |  1997-05-25  |  25KB  |  1,096 lines

  1. //Kasuha's DeathMatch Camera QC patch version 1.5
  2.  
  3. /////////////////////////////////////////////////////////////////////////////
  4. // KasCam definitions
  5. /////////////////////////////////////////////////////////////////////////////
  6.  
  7. // KasCam constants
  8.  
  9. float CAM_IDLE      = 0;   // Camera idle, nobody to look at
  10. float CAM_FIXED     = 1;   // Fixed-position camera
  11. float CAM_FLYBY     = 2;   // Fly-by camera
  12. float CAM_FOLLOW    = 3;   // Camera following a player
  13. float CAM_HAND      = 4;   // Hand-targeted camera
  14. float CAM_FREE      = 5;   // Flying hand-targeted camera
  15. float CAM_NOCLIP    = 6;   // No-clipping flying blabla
  16. float CAM_DEATH     = 7;   // Death camera
  17.  
  18. // KasCam variables
  19.  
  20. entity CamClient;          // Camera client
  21. entity CamTargEnt;         // Targeted entity
  22. vector CamPos;             // Current expected camera position
  23. vector CamTarget;          // Current expected targeted point
  24. vector CamNexTrg;          // Next target for idle mode
  25. vector CamAngV;            // Angle speed
  26. float  CamDist;            // Max distance for flyby mode
  27. float  CamMsgs;            // "take" messages ON/OFF
  28. float  CamState;           // Camera state
  29.  
  30. float  CamLastFrameTime;   // For time measure
  31. float  CamNextThink;       // Delay measure
  32. float  CamDrop;            // When drop from current mode
  33. float  CamForceTarget;     // How long to keep current target / idle mode
  34. entity CamLastTarg;        // Previous target
  35.  
  36. /////////////////////////////////////////////////////////////////////////////
  37. // end of KasCam definitions
  38. /////////////////////////////////////////////////////////////////////////////
  39.  
  40. // KasCam functions
  41.  
  42. entity(entity ent) CamCycle =
  43. {
  44.  ent = find(ent,classname,"player");
  45.  return ent;
  46. };
  47.  
  48. void(entity ent) CamVectors =
  49. {
  50.  makevectors(ent.v_angle);
  51. };
  52.  
  53. void(entity client, string s1, string s2, string s3, string s4, string s5, string s6) camcenterprint = #73;
  54.  
  55. void(entity ent, string tit) CamReport =
  56. {
  57.  local string s2,s3;
  58.  
  59.  if (ent.frags < 1) {
  60.   s2 = "no";
  61.  } else {
  62.   s2 = ftos(ent.frags);
  63.  }
  64.  if (ent.frags != 1) {
  65.   s3 = " frags";
  66.  } else {
  67.   s3 = " frag";
  68.  }
  69.  camcenterprint(self,tit,"\n\n\n",ent.netname," - ",s2,s3);
  70. };
  71.  
  72. // There is NO square root ?!
  73.  
  74. float(float num) CamSqrt =
  75. {
  76.  local float apr;
  77.  
  78.  if (num < 0.001)
  79.   return 0;
  80.  
  81.  if (num>1) {
  82.   apr = num;
  83.  } else {
  84.   apr = 1;
  85.  }
  86.  do {
  87.   apr = (num + (apr * apr)) / (2 * apr);
  88.  } while (fabs((apr * apr) - num) > (num * 0.001));
  89.  return apr;
  90. };
  91.  
  92. // Angle normalization
  93.  
  94. float(float a) CamReAngle =
  95. {
  96.  while (a>180) a = a - 360;
  97.  while (a<-180) a = a + 360;
  98.  return a;
  99. };
  100.  
  101. // Visibility test
  102.  
  103. float(vector vec) CamVisible =
  104. {
  105.  traceline(self.origin,vec,TRUE,self);
  106.  return ((trace_fraction == 1) && !((trace_inopen && trace_inwater)));
  107. };
  108.  
  109. entity() CamShoot =
  110. {
  111.  local entity ent,entx;
  112.  local vector vec;
  113.  local float d1,dx;
  114.  
  115.  makevectors(self.v_angle);
  116.  entx = world;
  117.  ent = CamCycle(world);
  118.  dx = 0;
  119.  while (ent != world) {
  120.   if (ent.deadflag == DEAD_NO) {
  121.    vec = ent.origin - self.origin;
  122.    vec = normalize(vec);
  123.    d1 = (v_forward_x * vec_x) + (v_forward_y * vec_y) + (v_forward_z * vec_z);
  124.    if (d1 > dx) {
  125.     if (CamVisible(ent.origin)) {
  126.      entx = ent;
  127.      dx = d1;
  128.     }
  129.    }
  130.   }
  131.   ent = CamCycle(ent);
  132.  }
  133.  return entx;
  134. };
  135.  
  136. float(float d, float a) CamHurry =
  137. {
  138.  local float dd,t,tt;
  139.  
  140.  if (d<0) a = 0 - a;
  141.  t = time - CamLastFrameTime;
  142.  tt = CamSqrt(d / a);
  143.  if (t > tt) {
  144.   return d;
  145.  } else {
  146.   return (a * t * ((2 * tt) - t));
  147.  }
  148. };
  149.  
  150. // Watch out! This is probably the most sophisticated routine ;-)
  151. // I spent 5 hours developing the algorithm
  152. // If you understand how it works in 3 minutes you're a guru :-)))
  153.  
  154. vector(float s, float v, float a) CamSmooth =
  155. {
  156.  local float dt,t1,t2,v2,as,sv2,b;
  157.  local vector vec;
  158.  
  159.  s = CamReAngle(s);
  160.  v2 = v / 2;
  161.  as = a * s;
  162.  sv2 = v2 * v2;
  163.  dt = time - CamLastFrameTime;
  164.  if (fabs(as) < sv2) {
  165.   b = v > 0;
  166.  } else {
  167.   b = s > 0;
  168.  }
  169.  if (b) {
  170.   t2 = CamSqrt((sv2 + as) / 2) / a;
  171.   a = 0 - a;
  172.  } else {
  173.   t2 = CamSqrt((sv2 - as) / 2) / a;
  174.  }
  175.  t1 = t2 - (v2 / a);
  176.  if (t1 > dt) {
  177.   s = (a * dt + v) * dt + s;
  178.   v = a * dt * 2 + v;
  179.  } else {
  180.   s = (a * t1 + v) * t1 + s;
  181.   v = a * t1 * 2 + v;
  182.   t1 = dt - t1;
  183.   if (t1 < t2) {
  184.    s = (v - (a * t1)) * t1 + s;
  185.    v = v - (a * t1 * 2);
  186.   } else {
  187.    s = 0;
  188.    v = 0;
  189.   }
  190.  }
  191.  vec_x = s;
  192.  vec_y = v;
  193.  return vec;
  194. };
  195.  
  196. float(entity ent) CamVisibleEnt =
  197. {
  198.  local vector vec;
  199.  
  200. // Three points: origin, bottom and eyes
  201.  if (CamVisible(ent.origin)) return TRUE;
  202.  vec = ent.origin;
  203.  vec_z = ent.absmin_z;
  204.  if (CamVisible(vec)) return TRUE;
  205.  vec_z = ent.absmax_z - 8;
  206.  return CamVisible(vec);
  207. };
  208.  
  209. float(vector vec) TryFlybyVector =
  210. {
  211.  local vector orig,vec1;
  212.  local float vl;
  213.  
  214.  vec1 = normalize(vec);
  215.  vec = 700 * vec1;
  216.  orig = CamTargEnt.origin;
  217.  orig_z = CamTargEnt.absmax_z - 8;
  218.  traceline(orig,orig+vec,TRUE,self);
  219.  if (trace_inopen && trace_inwater) return 1111;
  220.  trace_endpos = trace_endpos - vec1;
  221.  vl = vlen(CamTargEnt.origin - trace_endpos);
  222.  if (vl<50) return 1111;
  223.  if (pointcontents(trace_endpos) == CONTENT_SOLID) return 1111;
  224.  return fabs(333 - vl);
  225. };
  226.  
  227. // Angle moving;
  228.  
  229. float(float src,float dst,float spd) CamAngMove =
  230. {
  231.  local float d,dd;
  232.  
  233.  d = dst - src;
  234.  while (d>180) d = d - 360;
  235.  while (d<-180) d = d + 360;
  236.  if (fabs(d)>1.5) {
  237.   dd = CamHurry(d,spd);
  238.  } else {
  239.   dd = 0;
  240.  }
  241.  return src + dd;
  242. };
  243.  
  244. // Move camera towards ideal position (or just skip there)
  245.  
  246. void(float speedv, float speeda) CamUpdatePos =
  247. {
  248.  local vector vec, v1;
  249.  local float vl;
  250.  
  251. // Check destination visibility
  252.  traceline(self.origin,CamPos,TRUE,self);
  253.  if (trace_fraction != 1) {
  254.   speedv = 0;
  255.   speeda = 0;
  256.  }
  257. // Rotate the camera towards the target
  258. // and move it towards the ideal position
  259.  if (speedv == 0) {
  260.   setorigin(self,CamPos);
  261.  } else {
  262.   vec = CamPos - self.origin;
  263.   vl = vlen(vec);
  264.   vec = normalize(vec);
  265.   vl = CamHurry(vl,speedv);
  266.   vec = vl * vec;
  267.   setorigin(self,self.origin + vec);
  268.  }
  269.  self.fixangle = TRUE;
  270.  self.movetype = MOVETYPE_NONE;
  271.  if (CamState != CAM_DEATH) {
  272.   vec = vectoangles(CamTarget - CamPos);
  273.  } else {
  274.   vec = vectoangles(CamTarget - CamClient.origin);
  275.  }
  276.  vec_z = 0;
  277.  vec_x = CamReAngle(360 - vec_x);
  278.  vec_y = CamReAngle(vec_y);
  279.  if (vec_x > 70) {
  280.   vec_x = 70;
  281.  } else {
  282.   if (vec_x < -70) vec_x = -70;
  283.  }
  284.  if (speeda == 0) {
  285.   self.angles = vec;
  286.   CamAngV = '0 0 0';
  287.  } else {
  288.   v1 = CamSmooth(self.angles_x - vec_x,CamAngV_x,speeda);
  289.   CamAngV_x = v1_y;
  290.   self.angles_x = vec_x + v1_x;
  291.   v1 = CamSmooth(self.angles_y - vec_y,CamAngV_y,speeda);
  292.   CamAngV_y = v1_y;
  293.   self.angles_y = vec_y + v1_x;
  294.   self.angles_x = CamReAngle(self.angles_x);
  295.   self.angles_y = CamReAngle(self.angles_y);
  296.  }
  297.  self.v_angle = self.angles;
  298. };
  299.  
  300. void() CamSetAuto =
  301. {
  302.  CamPos = self.origin;
  303.  makevectors(self.v_angle);
  304.  CamTarget = self.origin+v_forward;
  305.  CamUpdatePos(0,0);
  306. };
  307.  
  308. void() CamGoIdle =
  309. {
  310.  CamSetAuto();
  311.  CamState = CAM_IDLE;
  312.  CamNextThink = time;
  313.  CamDrop = time;
  314.  CamNexTrg = CamTarget;
  315.  CamTargEnt = CamClient;
  316. };
  317.  
  318. void() CamGoDeath =
  319. {
  320.  CamAngV = '0 0 0';
  321.  CamPos = CamClient.origin;
  322.  CamState = CAM_DEATH;
  323.  CamNextThink = time + 1;
  324.  CamLastTarg = world;
  325. };
  326.  
  327. // FlyBy mode initialization
  328. // Targeted player is in CamTargEnt
  329.  
  330. void(entity newtarg) CamInitFlybyMode =
  331. {
  332.  local float f, max;
  333.  local vector vec, vec2;
  334.  local entity ent;
  335.  
  336. // Keep camera at this point some time...
  337.  CamNextThink = time + 0.4;
  338.  
  339. // Report selected player
  340.  if (CamTargEnt != newtarg) {
  341.   CamTargEnt = newtarg;
  342.   if (CamLastTarg != CamTargEnt) {
  343.    if (CamMsgs) {
  344.     CamReport(CamTargEnt,"Now taking");
  345.    }
  346.    CamLastTarg = newtarg;
  347.   }
  348.  }
  349.  vec = CamTargEnt.angles;
  350.  vec_x = 0;
  351.  makevectors (vec);
  352.  v_forward = 3 * v_forward;
  353.  max = 1000;
  354.  f = TryFlybyVector(v_forward + v_up + v_right);
  355.  if (f<max) {
  356.   max = f;
  357.   vec = trace_endpos;
  358.  }
  359.  f = TryFlybyVector(v_forward + v_up - v_right);
  360.  if (f<max) {
  361.   max = f;
  362.   vec = trace_endpos;
  363.  }
  364.  f = TryFlybyVector(v_forward + v_right);
  365.  if (f<max) {
  366.   max = f;
  367.   vec = trace_endpos;
  368.  }
  369.  f = TryFlybyVector(v_forward - v_right);
  370.  if (f<max) {
  371.   max = f;
  372.   vec = trace_endpos;
  373.  }
  374.  f = TryFlybyVector(v_forward + v_up);
  375.  if (f<max) {
  376.   max = f;
  377.   vec = trace_endpos;
  378.  }
  379.  f = TryFlybyVector(v_up - v_forward);
  380.  if (f<max) {
  381.   max = f;
  382.   vec = trace_endpos;
  383.  }
  384.  f = TryFlybyVector(v_up + v_right - v_forward);
  385.  if (f<max) {
  386.   max = f;
  387.   vec = trace_endpos;
  388.  }
  389.  f = TryFlybyVector(v_up - v_right - v_forward);
  390.  if (f<max) {
  391.   max = f;
  392.   vec = trace_endpos;
  393.  }
  394.  if (max >= 1000) {
  395.   CamGoIdle();
  396.   CamNextThink = time + 2;
  397.   return;
  398.  }
  399.  CamTarget = CamTargEnt.origin;
  400.  CamPos = vec;
  401.  CamState = CAM_FLYBY;
  402.  CamDist = 1.5 * vlen(CamPos - CamTarget);
  403.  if (CamDist < 500) CamDist = 500;
  404.  CamUpdatePos(0,0);
  405. };
  406.  
  407. vector() GetFollowCam =
  408. {
  409.  local vector vec, vec2;
  410.  
  411.  CamVectors(CamTargEnt);
  412.  vec = CamTargEnt.origin + (CamTargEnt.maxs_z + 4) * v_up;
  413.  traceline(CamTargEnt.origin,vec,FALSE,self);
  414.  vec = trace_endpos - normalize(vec);
  415.  vec2 = -100 * v_forward;
  416.  traceline(vec,vec+vec2,TRUE,self);
  417.  vec2 = trace_endpos - normalize(vec2);
  418.  if (CamVisible(vec2)) {
  419.   return vec2;
  420.  } else {
  421.   return vec;
  422.  }
  423. };
  424.  
  425. vector() GetFollowTrg =
  426. {
  427.  local vector vec;
  428.  
  429.  if (CamTargEnt.deadflag == DEAD_NO) {
  430.   CamVectors(CamTargEnt);
  431.   vec = CamTargEnt.origin + 2048 * v_forward;
  432.  } else {
  433.   vec = CamTargEnt.origin;
  434.  }
  435.  return vec;
  436. };
  437.  
  438. // Move the camera to the point it is looking at
  439.  
  440. void() CamHandJump =
  441. {
  442.  makevectors(self.v_angle);
  443.  traceline(self.origin,self.origin+2000*v_forward,TRUE,self);
  444.  CamPos=trace_endpos - normalize(trace_endpos-self.origin);
  445.  CamTarget = self.origin;
  446.  CamUpdatePos(0,0);
  447. };
  448.  
  449. // find n-th saved position
  450.  
  451. entity(float n) CamGetPos =
  452. {
  453.  local entity ent;
  454.  
  455.  ent = find(world,classname,"CamSavedPos");
  456.  while((n>0) && (ent!=world)) {
  457.   ent = find(ent,classname,"CamSavedPos");
  458.   n = n - 1;
  459.  }
  460.  return ent;
  461. };
  462.  
  463. // save actual position and angles
  464.  
  465. void(float n) CamSavePos =
  466. {
  467.  local entity ent;
  468.  
  469.  ent = CamGetPos(n);
  470.  if (ent!=world) {
  471.   ent.angles = self.angles;
  472.   ent.v_angle = self.v_angle;
  473.   setorigin(ent,self.origin);
  474.  }
  475. };
  476.  
  477. // save actual position and angles
  478.  
  479. void(float n) CamLoadPos =
  480. {
  481.  local entity ent;
  482.  
  483.  if ((CamState == CAM_HAND) || (CamState == CAM_FREE) || (CamState == CAM_NOCLIP)) {
  484.   ent = CamGetPos(n);
  485.   if (ent!=world) {
  486.    self.fixangle = TRUE;
  487.    self.angles = ent.angles;
  488.    self.v_angle = ent.v_angle;
  489.    setorigin(self,ent.origin);
  490.   }
  491.  }
  492. };
  493.  
  494. // Impulse handling
  495.  
  496. void() CamImpulses =
  497. {
  498.  local float c;
  499.  local entity ent;
  500.  
  501. // Choose target automatically
  502.  if (self.impulse == 100) {
  503.   CamGoIdle();
  504. // Choose target manually
  505.  } else if ((self.impulse > 100) && (self.impulse <150)) {
  506.   c = self.impulse - 100;
  507.   ent = world;
  508.   do {
  509.    ent = CamCycle(ent);
  510.    c = c - 1;
  511.   } while ((c>0) && (ent != world));
  512.   if (ent != world) {
  513.    if (ent.deadflag == DEAD_NO) {
  514.     CamInitFlybyMode(ent);
  515.     CamForceTarget = time + 10;
  516.     CamDrop = time + 60;
  517.    }
  518.   }
  519. // Save position
  520.  } else if((self.impulse>=180) && (self.impulse<=189)) {
  521.   c = self.impulse - 180;
  522.   CamSavePos (c);
  523. // Load position
  524.  } else if((self.impulse>=190) && (self.impulse<=199)) {
  525.   c = self.impulse - 190;
  526.   CamLoadPos (c);
  527. // Force FLYBY
  528.  } else if (self.impulse == 200) {
  529.   if (CamTargEnt != self) {
  530.    CamInitFlybyMode(CamTargEnt);
  531.   } else {
  532.    ent = CamShoot();
  533.    if (ent != world) {
  534.     CamInitFlybyMode(ent);
  535.     CamForceTarget = time + 10;
  536.     CamDrop = time + 60;
  537.    }
  538.   }
  539. // Force FOLLOW
  540.  } else if (self.impulse == 201) {
  541.   if (CamTargEnt != self) {
  542.    CamState = CAM_FOLLOW;
  543.   } else {
  544.    ent = CamShoot();
  545.    if (ent != world) {
  546.     CamTargEnt = ent;
  547.     if (CamTargEnt != CamLastTarg) {
  548.      CamLastTarg = CamTargEnt;
  549.      if (CamMsgs) {
  550.       CamReport(CamTargEnt,"Now Taking");
  551.      }
  552.     }
  553.     CamState = CAM_FOLLOW;
  554.     CamDrop = time + 60;
  555.     CamAngV = '0 0 0';
  556.     CamForceTarget = time + 10;
  557.    }
  558.   }
  559. // Force HAND
  560.  } else if (self.impulse == 202) {
  561.   if ((CamState != CAM_FLYBY) && (CamState != CAM_FIXED)) CamHandJump();
  562.   CamState = CAM_HAND;
  563.   self.movetype = MOVETYPE_NONE;
  564.   CamTargEnt = CamClient;
  565.   CamLastTarg = world;
  566. // Force FREE (FLY)
  567.  } else if (self.impulse == 203) {
  568.   CamState = CAM_FREE;
  569.   self.movetype = MOVETYPE_FLY;
  570.   CamTargEnt = CamClient;
  571.   CamLastTarg = world;
  572. // Force NOCLIP
  573.  } else if (self.impulse == 204) {
  574.   CamState = CAM_NOCLIP;
  575.   CamTargEnt = CamClient;
  576.   CamLastTarg = world;
  577.   self.movetype = MOVETYPE_NOCLIP;
  578. // Force FIXED
  579.  } else if (self.impulse == 205) {
  580.   if ((CamState == CAM_FLYBY) || (CamState == CAM_HAND)) {
  581.    CamSetAuto();
  582.    CamState = CAM_FIXED;
  583.    CamTargEnt = CamClient;
  584.    CamLastTarg = world;
  585.    CamDrop = time + 100000;
  586.    CamNextThink = time + 3;
  587.   }
  588. // Messages ON/OFF
  589.  } else if (self.impulse == 210) {
  590.   CamMsgs = !CamMsgs;
  591. // Report position
  592.  } else if (self.impulse == 211) {
  593.   bprint("Current camera position: ");
  594.   bprint(vtos(self.origin));
  595.   bprint("\n");
  596.  }
  597.  self.impulse = 0;
  598. };
  599.  
  600. // Update camera state according to current target
  601.  
  602. void() CamUpdValues =
  603. {
  604.  local float it;
  605.  
  606.  if ((CamTargEnt != CamClient) && (CamTargEnt.classname != "bodyque") && (CamTargEnt.health > 0)) {
  607. // Mask out items which change view color
  608.   it = IT_INVISIBILITY | IT_INVULNERABILITY | IT_SUIT | IT_QUAD;
  609.   self.items = (CamTargEnt.items | it) - it;
  610.   self.health = CamTargEnt.health;
  611.   self.armorvalue = CamTargEnt.armorvalue;
  612.   self.ammo_shells = CamTargEnt.ammo_shells;
  613.   self.ammo_nails = CamTargEnt.ammo_nails;
  614.   self.ammo_rockets = CamTargEnt.ammo_rockets;
  615.   self.ammo_cells = CamTargEnt.ammo_cells;
  616.   self.weapon = CamTargEnt.weapon;
  617.   self.currentammo = CamTargEnt.currentammo;
  618.  } else {
  619.   self.items = 0;
  620.   self.health = 111;
  621.   self.armorvalue = 111;
  622.   self.ammo_shells = 1;
  623.   self.ammo_nails = 1;
  624.   self.ammo_rockets = 1;
  625.   self.ammo_cells = 1;
  626.   self.weapon = IT_AXE;
  627.   self.currentammo = 11;
  628.  }
  629. };
  630.  
  631. // Overall health
  632.  
  633. float(entity ent) CamHealthVal =
  634. {
  635.  local float alldmg;
  636.  
  637. // First evaluate max damage if infinite armor
  638.  alldmg = ent.health/(1-ent.armortype);
  639. // Test for less armor
  640.  if (alldmg>(ent.health+ent.armorvalue)) {
  641.   alldmg = ent.health+ent.armorvalue;
  642.  }
  643. // And return maximum damage entity can bear
  644.  return alldmg;
  645. };
  646.  
  647. // IDLE mode think routine
  648.  
  649. void() CamIdleThink =
  650. {
  651.  local entity ent,ent2;
  652.  local vector vec;
  653.  local float p1,p2;
  654.  
  655. // Prepare a sentinel
  656.  ent2 = self;
  657.  p2 = -1;
  658.  p1 = 5 * random();
  659. // try to find some interesting target
  660.  if (p1 < 1) {
  661.   ent = CamCycle(world);
  662.   while (ent != world) {
  663. // Dead or dying are not interesting at this point
  664.    if (ent.deadflag == DEAD_NO) {
  665.     p1 = CamHealthVal(ent);
  666.     if (ent2 == self) {
  667.      ent2 = ent;
  668.      p2 = p1;
  669.     } else {
  670.      if (p2<p1) {
  671.       ent2 = ent;
  672.       p2 = p1;
  673.      }
  674.     }
  675.    }
  676.    ent = CamCycle(ent);
  677.   }
  678.  } else if (p1 < 2) {
  679.   ent = CamCycle(world);
  680.   while (ent != world) {
  681. // Dead or dying are not interesting at this point
  682.    if (ent.deadflag == DEAD_NO) {
  683.     p1 = ent.frags;
  684.     if (ent2 == self) {
  685.      ent2 = ent;
  686.      p2 = p1;
  687.     } else {
  688.      if (p2<p1) {
  689.       ent2 = ent;
  690.       p2 = p1;
  691.      }
  692.     }
  693.    }
  694.    ent = CamCycle(ent);
  695.   }
  696.  } else {
  697.   p2 = 0;
  698.   ent = CamCycle(world);
  699.   while (ent != world) {
  700.    if (ent.deadflag == DEAD_NO) p2 = p2 + 1;
  701.    ent = CamCycle(ent);
  702.   }
  703.   if (p2 > 0) {
  704.    p2 = p2 * random();
  705.    ent = world;
  706.    do {
  707.     do {
  708.      ent = CamCycle(ent);
  709.     } while (ent.deadflag != DEAD_NO);
  710.     p2 = p2 - 1;
  711.    } while (p2 > 0);
  712.    if (ent != world) ent2 = ent;
  713.   }
  714.  }
  715. // If an interesting object found
  716.  if (ent2 != self) {
  717. // Go to FlyBy mode
  718.   CamInitFlybyMode (ent2);
  719.   CamForceTarget = time + 10;
  720.   CamDrop = time + 60;
  721.  } else {
  722. // Idle moves
  723.   CamTargEnt = CamClient;
  724.   traceline(CamPos,CamTarget,TRUE,self);
  725.   if (trace_fraction != 1) CamTarget = trace_endpos;
  726.   vec_x = 140 * random () - 70;
  727.   vec_y = 360 * random ();
  728.   vec_z = 0;
  729.   makevectors(vec);
  730.   vec = 2000 * v_forward;
  731.   vec = CamPos + vec;
  732.   traceline(CamPos, vec, TRUE, self);
  733.   if (trace_fraction != 1) vec = trace_endpos;
  734.   p1 = vlen(vec - CamPos);
  735.   p2 = vlen(CamTarget - CamPos);
  736.   if (p1 > p2) {
  737.    CamNexTrg = vec;
  738.   }
  739.   if (CamNextThink < time) {
  740.    CamNextThink = time + 3 + (2 * random());
  741.    CamTarget = CamNexTrg;
  742.   }
  743.   if (CamDrop < time) {
  744.    vec = CamPos + 0.97 * (CamTarget - CamPos);
  745.    traceline(self.origin,vec, TRUE, self);
  746.    if (trace_fraction == 1) {
  747.     CamPos = vec;
  748.     CamDrop = time + 8 + (5 * random());
  749.    }
  750.   }
  751.  }
  752. };
  753.  
  754. // FLYBY mode thinking routine
  755.  
  756. void() CamFlyByThink =
  757. {
  758.  local float p0,p1,grad;
  759.  local vector vec;
  760.  local entity ent;
  761.  
  762. // CamTarget is set to player
  763. // Check if the player is not dead
  764.  if (CamTargEnt.deadflag != DEAD_NO) {
  765.    if (CamMsgs) CamReport(CamTargEnt,"R.I.P.");
  766.    CamGoDeath();
  767.    CamDrop = time + 5;
  768.    return;
  769.  }
  770. // All other restrictions apply after some time
  771. // Test player visibility
  772. // If player not visible place another camera
  773.  p1 = vlen(CamPos - CamTargEnt.origin);
  774.  if ((CamVisibleEnt(CamTargEnt) && (CamDist > p1)) || (CamNextThink > time)) {
  775.   CamTarget = CamTargEnt.origin;
  776.  } else {
  777.   CamInitFlybyMode (CamTargEnt);
  778.  }
  779. // Check for FOLLOW mode change
  780. // Player has to be near
  781. // And looking away
  782. // And the destination point must be visible
  783.  p1 = vlen(CamTargEnt.origin - self.origin);
  784.  if (p1 < 170) {
  785. // Player is near enough
  786. // Now if it points away
  787.   grad = fabs(CamTargEnt.angles_y - self.angles_y);
  788.   if (grad > 180) grad = 360 - grad;
  789.   if (grad < 30) {
  790. // Calculate following point
  791.    vec = GetFollowCam();
  792.    if (CamVisible(vec)) {
  793.     CamState = CAM_FOLLOW;
  794.     return;
  795.    }
  796.   }
  797.  }
  798.  p0 = 0;
  799.  p1 = 0;
  800.  if (CamForceTarget < time) {
  801.   ent = CamCycle(world);
  802.   while (ent != world) {
  803.    p0 = p0 + 1;
  804.    if (ent.deadflag == DEAD_NO) {
  805.     if (CamVisible(ent.origin)) {
  806.      p1 = p1 + 1;
  807.     }
  808.    }
  809.    ent = CamCycle(ent);
  810.   }
  811.  }
  812.  if (p0<4) {
  813.   p0 = 2;
  814.  } else if (p0<8) {
  815.   p0 = 3;
  816.  } else {
  817.   p0 = 4;
  818.  }
  819.  if (p1 > p0) {
  820.   CamTargEnt = CamClient;
  821.   CamLastTarg = world;
  822.   CamState = CAM_FIXED;
  823.   CamDrop = time + 15;
  824.   CamNextThink = time + 3;
  825.  }
  826.  if (CamDrop < time) {
  827.   CamGoIdle();
  828.  }
  829. };
  830.  
  831. // FOLLOW mode thinking routine
  832.  
  833. void() CamFollowThink =
  834. {
  835.  local entity ent;
  836.  local vector vec;
  837.  
  838. // Check player death
  839.  if (CamTargEnt.deadflag != DEAD_NO) {
  840.   if (CamMsgs) CamReport(CamTargEnt,"R.I.P.");
  841.   CamGoDeath();
  842.   CamDrop = time + 5;
  843.   return;
  844.  } else {
  845.   if (CamVisibleEnt(CamTargEnt)) {
  846.    CamPos = GetFollowCam();
  847.    CamTarget = GetFollowTrg();
  848.    if (pointcontents(CamPos) == CONTENT_SOLID) CamInitFlybyMode(CamTargEnt);
  849.   } else {
  850.    CamInitFlybyMode(CamTargEnt);
  851.   }
  852.  }
  853.  if (CamDrop < time) {
  854.   CamGoIdle();
  855.  }
  856. };
  857.  
  858. // FIXED mode thinking routine
  859.  
  860. void() CamFixedThink =
  861. {
  862.  local vector vec;
  863.  local entity ent;
  864.  local float cang;
  865.  local float a;
  866.  local float cscr; // count of targets on screen
  867.  local float maxscr; // minimum angle on screen
  868.  local float minscr; // maximum angle on screen
  869.  local float maxlo; // maximum angle of lowers
  870.  local float minhi; // minimum angle of highers
  871.  local vector scrv; // onscreen origin sum
  872.  local vector hiv; // lower optimum
  873.  local vector lov; // higher optimum
  874.  local float c;
  875.  
  876.  cang = self.v_angle_y;
  877.  cscr = 0;
  878.  maxscr = -45;
  879.  minscr = 45;
  880.  maxlo = -181;
  881.  minhi = 181;
  882.  scrv = '0 0 0';
  883.  c = 0;
  884.  ent = CamCycle(world);
  885.  while (ent != world) {
  886.   if (ent.deadflag == DEAD_NO) {
  887.    if (CamVisible(ent.origin)) {
  888. // Possible target is visible
  889. // Look if it is "on screen"
  890.     c = c + 1;
  891.     vec = vectoangles(ent.origin - self.origin);
  892.     a = vec_y - cang;
  893.     while (a > 180) a = a - 360;
  894.     while (a < -180) a = a + 360;
  895.     if (fabs(a)<45) {
  896. // entity is "on screen"
  897.      cscr = cscr + 1;
  898.      scrv = scrv + ent.origin;
  899.      if (a < minscr) minscr = a;
  900.      if (a > maxscr) maxscr = a;
  901.     } else {
  902.      if (a > 0) {
  903.       if (a < minhi) {
  904.        minhi = a;
  905.        hiv = ent.origin;
  906.       }
  907.      } else {
  908.       if (a > maxlo) {
  909.        maxlo = a;
  910.        lov = ent.origin;
  911.       }
  912.      }
  913.     }
  914.    }
  915.   }
  916.   ent = CamCycle(ent);
  917.  }
  918.  if (c > 0) {
  919.   if (c > 1) CamNextThink = time + 3;
  920.   if (cscr < c) {
  921.    if ((cscr == 0) || ((maxscr - maxlo) <= 90) || ((minhi - minscr) <= 90)) {
  922.     cscr = cscr + 1;
  923.     if ((maxscr - maxlo) > (minhi - minscr)) {
  924.      scrv = scrv + hiv;
  925.     } else {
  926.      scrv = scrv + lov;
  927.     }
  928.    }
  929.   }
  930.   scrv_x = scrv_x / cscr;
  931.   scrv_y = scrv_y / cscr;
  932.   scrv_z = scrv_z / cscr;
  933.   CamTarget = scrv;
  934.  }
  935.  CamPos = self.origin;
  936.  if ((CamNextThink < time) || (CamDrop < time)) {
  937.   CamGoIdle();
  938.  }
  939. };
  940.  
  941. void(entity ent,entity que) CamCopyBody =
  942. {
  943.  if (ent == CamTargEnt) {
  944.   CamTargEnt = que;
  945.   if (CamState != CAM_DEATH) {
  946.    CamGoDeath();
  947.    CamDrop = time + 5;
  948.   }
  949.  } else if (que == CamTargEnt) {
  950.   CamTargEnt = CamClient;
  951.  }
  952. };
  953.  
  954. // DEATH mode think
  955. void() CamDeathThink =
  956. {
  957.  local float f;
  958.  
  959.  if (CamDrop < time) {
  960.   CamGoIdle();
  961.   return;
  962.  }
  963.  if (CamTargEnt != CamClient) {
  964.   f = vlen(CamClient.origin - CamPos);
  965.   if ((f>1) || (CamAngV != '0 0 0')) {
  966.    f = time + 0.5;
  967.    if (CamNextThink < f) {
  968.     CamNextThink = f;
  969.    }
  970.   }
  971.  }
  972.  if (time > CamNextThink) {
  973.   CamGoIdle();
  974.  } else {
  975.   if (CamTargEnt != CamClient) {
  976.    CamTarget = CamTargEnt.origin;
  977.   }
  978.  }
  979.  if (CamTargEnt != CamClient) {
  980.   if (!CamVisible(CamTarget)){
  981.    CamInitFlybyMode(CamTargEnt);
  982.    CamState = CAM_DEATH;
  983.    CamNextThink = time + 2;
  984.    if (!CamVisible(CamTarget)){
  985.     if (CamTargEnt.velocity == '0 0 0'){
  986.      CamGoIdle();
  987.     }
  988.    }
  989.   }
  990.   if (CamTargEnt.velocity != '0 0 0') {
  991.    CamNextThink = time + 2;
  992.   }
  993.  }
  994.  if (vlen(CamPos - CamTarget)>60) {
  995.   CamPos = CamPos - CamTarget;
  996.   CamPos = normalize(CamPos);
  997.   CamPos = 59 * CamPos + CamTarget;
  998.  }
  999. };
  1000.  
  1001. // Main camera thinking routine
  1002. // Called every frame
  1003.  
  1004. void() CamThink =
  1005. {
  1006. // Update visible values (health, armor, ...)
  1007.  CamUpdValues();
  1008.  self.velocity = '0 0 0';
  1009. // Status depending handling
  1010.  if (CamState == CAM_IDLE) {
  1011.   CamIdleThink();
  1012.   CamUpdatePos(1,50);
  1013.  } else if (CamState == CAM_FLYBY) {
  1014.   CamFlyByThink();
  1015.   CamUpdatePos(0,500);
  1016.  } else if (CamState == CAM_FOLLOW) {
  1017.   CamFollowThink();
  1018.   CamUpdatePos(800,1000);
  1019.  } else if (CamState == CAM_FIXED) {
  1020.   CamFixedThink();
  1021.   CamUpdatePos(0,70);
  1022.  } else if (CamState == CAM_DEATH) {
  1023.   CamDeathThink();
  1024.   CamUpdatePos(100,150);
  1025. // } else if (CamState == CAM_HAND) { -- nothing to do
  1026. // } else if (CamState == CAM_FREE) { -- nothing to do
  1027. // } else if (CamState == CAM_NOCLIP) { -- nothing to do
  1028. // } else if (CamState == ...
  1029.  }
  1030.  
  1031. // Impulse handling (standard is not active)
  1032.  CamImpulses();
  1033. // Update time
  1034.  CamLastFrameTime = time;
  1035. };
  1036.  
  1037.  
  1038. // CamClient initialization
  1039.  
  1040. void() CamClientInit =
  1041. {
  1042.  local entity ent;
  1043.  
  1044.  self.classname = "CameraClient";
  1045.  setmodel (self, string_null);
  1046.  self.weaponmodel = string_null;
  1047.  setsize (self, '0 0 0', '0 0 0');
  1048.  self.velocity = '0 0 0';
  1049.  self.view_ofs = '0 0 0';
  1050.  self.movetype = MOVETYPE_NONE;
  1051.  self.solid = SOLID_NOT;
  1052.  self.takedamage = DAMAGE_NO;
  1053.  self.fixangle = TRUE;
  1054.  self.nextthink = -1;
  1055.  self.colormap = 0;
  1056.  CamClient = self;
  1057.  CamPos = self.origin;
  1058.  makevectors(self.v_angle);
  1059.  CamTarget = CamPos + 100 * v_forward;
  1060.  CamTargEnt = CamClient;
  1061.  CamLastTarg = world;
  1062.  CamMsgs = TRUE;
  1063.  CamAngV = '0 0 0';
  1064.  CamNextThink = time;
  1065.  CamForceTarget = time;
  1066.  CamLastFrameTime = time;
  1067. // now reset all saved positions
  1068.  ent = find(world,classname,"CamSavedPos");
  1069.  while(ent!=world) {
  1070.   ent.v_angle = self.v_angle;
  1071.   ent.angles = self.angles;
  1072.   setorigin(ent,self.origin);
  1073.   ent = find(ent,classname,"CamSavedPos");
  1074.  }
  1075.  CamGoIdle();
  1076.  bprint("Camera running");
  1077. };
  1078.  
  1079. // Main initialization
  1080.  
  1081. void() CamSpawn =
  1082. {
  1083.  local float i;
  1084.  local entity ent;
  1085.  
  1086. // initialize camera
  1087.  CamClient = world;
  1088. // init saved positions
  1089.  i=10;
  1090.  do {
  1091.   ent = spawn();
  1092.   ent.classname = "CamSavedPos";
  1093.   i = i - 1;
  1094.  } while(i>0);
  1095. };
  1096.